using System;
using System.IO;
using System.Xml;
using System.Drawing;
using System.Windows.Forms;
using System.Globalization;

using needle.UI.Controls.Flat.Resources;
using needle.UI.Controls.Flat.Resources.Keys;
using needle.UI.Controls.Flat.Windows.Forms;
using needle.UI.Controls.Flat.Windows.Forms.Helpers;
using needle.UI.Controls.Flat.Windows.Forms.Collections;

namespace needle.UI.Controls.Flat.Windows.Forms
{
	public class TabGroupSequence : TabGroupBase, IResizeSource
	{
	    protected const int SpacePrecision = 3;
	
        protected Control mcontrol;
        protected Direction mdirection;
        protected TabGroupBaseCollection mchildren;
        
		#region Constructors
		
		public TabGroupSequence(TabbedGroups tabbedGroups)
            : base(tabbedGroups)
        {
            InternalConstruct(tabbedGroups, Direction.Horizontal);
        }
    
        public TabGroupSequence(TabbedGroups tabbedGroups, TabGroupBase parent)
            : base(tabbedGroups, parent)
        {
		    InternalConstruct(null, Direction.Horizontal);
        }

        public TabGroupSequence(TabbedGroups tabbedGroups, TabGroupBase parent, Direction direction)
            : base(tabbedGroups, parent)
        {
            InternalConstruct(null, direction);
        }

        protected void InternalConstruct(Control control, Direction direction)
        {
            if (control == null) 
            {
                mcontrol = new Panel();
            }
            else
            {
                mcontrol = control;
            }
            
            mcontrol.Resize += new EventHandler(OnControlResize);
            
            mdirection = direction;
            
            mchildren = new TabGroupBaseCollection();
        }

		#endregion
        
		#region Dispose

		public override void Dispose()
		{
			if (mcontrol != null)
			{
				mcontrol.Resize -= new EventHandler(OnControlResize);
			}
			this.Dispose();
		}

		#endregion
		
		#region Overrides
		
		public override void Notify(NotifyCode code)
        {
            switch(code)
            {
                case NotifyCode.ProminentChanged:
                case NotifyCode.MinimumSizeChanged:
                    RepositionChildren();
                    break;
                case NotifyCode.ResizeBarVectorChanged:
                    RepositionChildren();
                    break;
                case NotifyCode.ResizeBarColorChanged:
                    if (mchildren.Count > 1)
                    {
                        mcontrol.Invalidate();
                    }
                    break;
            }
            
            foreach(TabGroupBase child in mchildren)
                child.Notify(code);
        }

        public override bool ContainsProminent(bool recurse)
        {
            TabGroupLeaf prominent = mtabbedGroups.ProminentLeaf;
            
            if (prominent == null)
                return false;
                
            foreach(TabGroupBase group in mchildren)
                if (group.IsLeaf)
                    if (group == prominent)
                        return true;

            if (recurse)
            {
                foreach(TabGroupBase group in mchildren)
                    if (group.IsSequence)
                        if (group.ContainsProminent(recurse))
                            return true;
            }
                                    
            return false;                            
        }

        public override void SaveToXml(XmlTextWriter xmlOut)
        {
            xmlOut.WriteStartElement("Sequence");
            xmlOut.WriteAttributeString("Count", mchildren.Count.ToString(CultureInfo.CurrentCulture));
            xmlOut.WriteAttributeString("Unique", munique.ToString(CultureInfo.CurrentCulture));
            xmlOut.WriteAttributeString("Space", mspace.ToString(CultureInfo.CurrentCulture));
            xmlOut.WriteAttributeString("Direction", mdirection.ToString(CultureInfo.CurrentCulture));

            foreach(TabGroupBase tgb in mchildren)
                tgb.SaveToXml(xmlOut);
                
            xmlOut.WriteEndElement();
        }

        public override void LoadFromXml(XmlTextReader xmlIn)
        {
            string rawCount = xmlIn.GetAttribute(0);
            string rawUnique = xmlIn.GetAttribute(1);
            string rawSpace = xmlIn.GetAttribute(2);
            string rawDirection = xmlIn.GetAttribute(3);

            int count = Convert.ToInt32(rawCount, CultureInfo.CurrentCulture);
            int unique = Convert.ToInt32(rawUnique, CultureInfo.CurrentCulture);
            Decimal space = Convert.ToDecimal(rawSpace, CultureInfo.CurrentCulture);
            Direction direction = (rawDirection == "Horizontal" ? Direction.Horizontal : 
                                                                  Direction.Vertical);
            
            munique = unique;
            mspace = space;
            mdirection = direction;
            
            for(int i=0; i<count; i++)
            {
                if (!xmlIn.Read())
                    throw new ArgumentException(ResourceLibrary.GetString(WindowsControlsResourceKeys.InaccessibleNode, WindowsControlsResourceKeys.Root));

                TabGroupBase newElement = null;

                if (xmlIn.Name == "Sequence")
                    newElement = new TabGroupSequence(mtabbedGroups, this);
                else if (xmlIn.Name == "Leaf")
                    newElement = new TabGroupLeaf(mtabbedGroups, this);
                else
                    throw new ArgumentException(ResourceLibrary.GetString(WindowsControlsResourceKeys.InaccessibleNode, WindowsControlsResourceKeys.Root));
            
                bool expectEndElement = !xmlIn.IsEmptyElement;

                newElement.LoadFromXml(xmlIn);
                   
                Add(newElement);

                if (expectEndElement)
                {
                    if (!xmlIn.Read())
                        throw new ArgumentException(ResourceLibrary.GetString(WindowsControlsResourceKeys.InaccessibleNode, WindowsControlsResourceKeys.Root));

                    if (xmlIn.NodeType != XmlNodeType.EndElement)
                        throw new ArgumentException(ResourceLibrary.GetString(WindowsControlsResourceKeys.FinalElementNotFound, WindowsControlsResourceKeys.Root));
                }
            }
        }

		#endregion

		#region Virtuals

		protected void DeltaGroupSpace(TabGroupBase group, int vector)
		{
			Rectangle clientRect = mcontrol.ClientRectangle;

			int space;

			int newLength = vector;
			
			if (mdirection == Direction.Vertical)
			{
				space = clientRect.Height;

				newLength += group.GrouparamControl.Height;
				newLength -= group.MinimumSize.Height;
			}
			else
			{
				space = clientRect.Width;

				newLength += group.GrouparamControl.Width;
				newLength -= group.MinimumSize.Width;
			}

			int barSpace = 0;

			int[] positions = new int[mcontrol.Controls.Count];

			AllocateMandatorySizes(ref positions, ref barSpace, ref space);

			Decimal newPercent = 0m;

			if ((newLength > 0) && (space > 0))
				newPercent = (Decimal)newLength / (Decimal)space * 100m;

			Decimal reallocate = newPercent - group.Space;

			TabGroupBase nextGroup = mchildren[mchildren.IndexOf(group) + 1];

			if ((nextGroup.Space - reallocate) < 0m)
				reallocate = nextGroup.Space;
	
			group.Space += reallocate;

			nextGroup.Space -= reallocate;
			
			RepositionChildren();
		}
		
		protected void CompactRemoveEmptyTabLeafs(TabbedGroups.CompactFlags flags)
        {
            if ((flags & needle.UI.Controls.Flat.Windows.Forms.TabbedGroups.CompactFlags.RemoveEmptyTabLeaf) != 0)
            {
                int count = mchildren.Count;
                
                for(int index=0; index<count; index++)
                {
                    if (mchildren[index].IsLeaf)
                    {
                        TabGroupLeaf tgl = (TabGroupLeaf)mchildren[index];
                        
                        if (tgl.Count == 0)
                        {
                            if (mtabbedGroups.ActiveLeaf == tgl)
                            {
                                TabGroupLeaf newLeaf = mtabbedGroups.NextLeaf(tgl);
                                
                                if (newLeaf == null)
                                    newLeaf = mtabbedGroups.PreviousLeaf(tgl);
                                    
                                mtabbedGroups.ActiveLeaf = newLeaf;
                            }

                            RemoveAt(index);
                            
                            count--;
                            
                            index--;
                        
                            if (mtabbedGroups.AutoCalculateDirty)
                                mtabbedGroups.Dirty = true;
                        }
                    }
                }
            }
        }

        protected void CompactRemoveEmptyTabSequences(TabbedGroups.CompactFlags flags)
        {
            if ((flags & needle.UI.Controls.Flat.Windows.Forms.TabbedGroups.CompactFlags.RemoveEmptyTabSequence) != 0)
            {
                int count = mchildren.Count;
                
                for(int index=0; index<count; index++)
                {
                    if (mchildren[index].IsSequence)
                    {
                        TabGroupSequence tgs = (TabGroupSequence)mchildren[index];
                        
                        if (tgs.Count == 0)
                        {
                            RemoveAt(index);
                            
                            count--;
                            
                            index--;

                            if (mtabbedGroups.AutoCalculateDirty)
                                mtabbedGroups.Dirty = true;
                        }
                    }
                }
            }
        }

        protected void CompactReduceSingleEntries(TabbedGroups.CompactFlags flags)
        {
            bool changed = false;
        
            if ((flags & needle.UI.Controls.Flat.Windows.Forms.TabbedGroups.CompactFlags.ReduceSingleEntries) != 0)
            {
                int count = mchildren.Count;
                
                for(int index=0; index<count; index++)
                {
                    if (mchildren[index].IsSequence)
                    {
                        TabGroupSequence tgs = (TabGroupSequence)mchildren[index];
                        
                        if (tgs.Count == 1)
                        {
                            Decimal temp = tgs.RealSpace;
                            
                            TabGroupBase child = tgs[0];
                            
                            child.SetParent(this);
                            
                            int childPos = mcontrol.Controls.IndexOf(tgs.GrouparamControl);
                            
                            ControlUtilities.RemoveAt(mcontrol.Controls, childPos);
                            
                            mcontrol.Controls.Add(child.GrouparamControl);
                            mcontrol.Controls.SetChildIndex(child.GrouparamControl, childPos);
                            
                            mchildren.RemoveAt(index);
                            mchildren.Insert(index, child);
                            
                            child.RealSpace = temp;

                            changed = true;                

                            if (mtabbedGroups.AutoCalculateDirty)
                                mtabbedGroups.Dirty = true;
                        }
                    }
                }
            }

            if (changed)
                RepositionChildren();
        }
        
        protected void CompactReduceSameDirection(TabbedGroups.CompactFlags flags)
        {
            bool changed = false;
        
            if ((flags & needle.UI.Controls.Flat.Windows.Forms.TabbedGroups.CompactFlags.ReduceSameDirection) != 0)
            {
                int count = mchildren.Count;
                
                for(int index=0; index<count; index++)
                {
                    if (mchildren[index].IsSequence)
                    {
                        TabGroupSequence tgs = (TabGroupSequence)mchildren[index];
                        
                        if (mdirection == tgs.Direction)
                        {
                            Decimal temp = tgs.RealSpace;

                            int childPos = mcontrol.Controls.IndexOf(tgs.GrouparamControl);

                            if (childPos > 0)
                                ControlUtilities.RemoveAt(mcontrol.Controls, childPos);
                                
                            ControlUtilities.RemoveAt(mcontrol.Controls, childPos);

                            mchildren.RemoveAt(index);
                            
                            count--;

                            Decimal totalAllocated = 0m;

                            int subCount = tgs.Count;
                            
                            bool firstInsert = true;
                
                            for(int subIndex=0; subIndex<subCount; subIndex++)
                            {
                                TabGroupBase tgb = tgs[subIndex];
                            
                                Decimal orig = tgb.RealSpace;
                                
                                Decimal update = Decimal.Round(temp / 100 * orig, SpacePrecision);
                            
                                totalAllocated += update;
                            
                                tgb.RealSpace = update;
                                
                                tgb.SetParent(this);

                                if ((childPos > 0) && !firstInsert)
                                {
                                    ResizeBar bar = new ResizeBar(mdirection, this);

                                    mcontrol.Controls.Add(bar);
                                    mcontrol.Controls.SetChildIndex(bar, childPos++);
                                }
                            
                                mcontrol.Controls.Add(tgb.GrouparamControl);
                                mcontrol.Controls.SetChildIndex(tgb.GrouparamControl, childPos++);
                                mchildren.Insert(index, tgb);
                                
                                index++;
                                count++;
                                firstInsert = false;
                            }
                            
                            mchildren[index-1].RealSpace +=  temp - totalAllocated;      
                            
                            changed = true;                

                            if (mtabbedGroups.AutoCalculateDirty)
                                mtabbedGroups.Dirty = true;
                        }
                    }
                }
            }
            
            if (changed)
                RepositionChildren();
        }

        protected TabGroupBase Add(TabGroupBase group)
        {
            mchildren.Add(group);

            if (mchildren.Count == 1) 
            {
                mcontrol.Controls.Add(group.GrouparamControl);
            }
            else
            {
                ResizeBar bar = new ResizeBar(mdirection, this);
                
                mcontrol.Controls.Add(bar);
                
                mcontrol.Controls.Add(group.GrouparamControl);
            }
            
            if (!mtabbedGroups.Initializing)
            {
                AllocateSpace(group);
                
                RepositionChildren();
            }
            
            if (mtabbedGroups.AutoCalculateDirty)
                mtabbedGroups.Dirty = true;

            return group;
        }
    
        protected TabGroupBase Insert(int index, TabGroupBase group)
        {
            if (index < 0)
                throw new ArgumentOutOfRangeException("index", index, ResourceLibrary.GetString(CommonResourceKeys.LargerIndexThanZero, CommonResourceKeys.Root));
                
            if (index >= mchildren.Count)
                throw new ArgumentOutOfRangeException("index", index, ResourceLibrary.GetString(WindowsControlsResourceKeys.CantInsert, WindowsControlsResourceKeys.Root));
        
            mchildren.Insert(index, group);

            ResizeBar bar = new ResizeBar(mdirection, this);
                
            mcontrol.Controls.Add(bar);
                
            mcontrol.Controls.Add(group.GrouparamControl);

            if (index == 0)
            {
                mcontrol.Controls.SetChildIndex(bar, 0);
                mcontrol.Controls.SetChildIndex(group.GrouparamControl, 0);
            }
            else
            {
                int	pos = index * 2 - 1;

                mcontrol.Controls.SetChildIndex(bar, pos++);
                mcontrol.Controls.SetChildIndex(group.GrouparamControl, pos);
            }
            
            AllocateSpace(group);
            
            RepositionChildren();

            if (mtabbedGroups.AutoCalculateDirty)
                mtabbedGroups.Dirty = true;

            return group;
        }

		protected void AllocateSpace(TabGroupBase newGroup)
		{
			if (mchildren.Count == 1)
			{
				newGroup.Space = 100m;
			}
			else
			{
				Decimal newSpace = 100m / mchildren.Count;

				Decimal reduceSpace = newSpace / (mchildren.Count - 1);

				Decimal allocatedSpace = 0m;

				foreach(TabGroupBase group in mchildren)
				{
					if (group != newGroup)
					{
						Decimal currentSpace = group.Space;

						Decimal xferSpace = reduceSpace;

						if (currentSpace < xferSpace)
							xferSpace = currentSpace;

						currentSpace -= xferSpace;
                        
						currentSpace = Decimal.Round(currentSpace, SpacePrecision);
                        
						group.Space = currentSpace;

						allocatedSpace += currentSpace;
					}
				}

				newGroup.Space = 100m - allocatedSpace;
			}
		}            
        
		protected void RemoveWindowSpace(Decimal space)
		{
			if (mchildren.Count != 0)
			{
				if (mchildren.Count == 1)
				{
					mchildren[0].Space = 100m;
				}
				else
				{
					if (space > 0)
					{
						Decimal totalAllocated = 0m;

						Decimal freedSpace = space / mchildren.Count;

						foreach(TabGroupBase group in mchildren)
						{
							Decimal newSpace = Decimal.Round(group.Space + freedSpace, SpacePrecision);

							group.Space = newSpace;

							totalAllocated += newSpace;
						}

						if (totalAllocated > 100m)
						{
							mchildren[0].Space -= totalAllocated - 100m;
						}
						else if (totalAllocated < 100m)
						{
							mchildren[0].Space += 100m - totalAllocated;
						}
					}
				}
			}
		}
                
		protected void RepositionChildren()
		{
			Rectangle clientRect = mcontrol.ClientRectangle;

			if (mchildren.Count > 0)
			{
				int space;
			
				int delta;

				if (mdirection == Direction.Vertical)
				{
					space = clientRect.Height;
					delta = clientRect.Top;
				}
				else
				{
					space = clientRect.Width;
					delta = clientRect.Left;
				}

				if (space < 0)
					space = 0;

				int barSpace = 0;
				int allocation = space;

				int[] positions = new int[mcontrol.Controls.Count];

				AllocateMandatorySizes(ref positions, ref barSpace, ref space);

				if (space > 0)
				{
					AllocateRemainingSpace(ref positions, space);
				}

				RepositionChildren(ref positions, clientRect, delta);
			}
		}

		protected void AllocateMandatorySizes(ref int[] positions, ref int barSpace, ref int space)
		{
			for(int index=0, child=0; index<mcontrol.Controls.Count; index++)
			{
				ResizeBar bar = mcontrol.Controls[index] as ResizeBar;

				if (bar != null)
				{
					positions[index] = bar.Length;
					barSpace += positions[index];
				}
				else
				{
					Size minimal = mchildren[child++].MinimumSize;
					if (mdirection == Direction.Vertical)
						positions[index] = minimal.Height;
					else
						positions[index] = minimal.Width;
				}

				space -= positions[index];
			}			
		}

		protected void AllocateRemainingSpace(ref int[] positions, int windowSpace)
		{
			int allocated = 0;

			for(int index=0, childIndex=0; index<mcontrol.Controls.Count; index++)
			{
				Control c = mcontrol.Controls[index];
                
				bool isResizeBar = (c is ResizeBar);

				if (!isResizeBar)
				{
					int extra;
					
					extra = (int)(windowSpace / 100m * mchildren[childIndex++].Space);

					if (childIndex == mchildren.Count)
					{
						extra = windowSpace - allocated;
					}

					positions[index] += extra;

					allocated += extra;
				}
			}
		}

		protected void RepositionChildren(ref int[] positions, Rectangle clientRect, int delta)
		{
			for(int index=0; index<mcontrol.Controls.Count; index++)
			{
				int newDelta = positions[index];

				ResizeBar bar = mcontrol.Controls[index] as ResizeBar;

				if (bar != null)
				{
					if (mdirection == Direction.Vertical)
					{
						bar.Location = new Point(clientRect.X, delta);
						bar.Width = clientRect.Width;
						bar.Height = newDelta;

						delta += newDelta;
					}
					else
					{
						bar.Location = new Point(delta, clientRect.Y);
						bar.Height = clientRect.Height;
						bar.Width = newDelta;

						delta += newDelta;
					}
				}
				else
				{
					Control c = mcontrol.Controls[index];

					if (c != null)
					{
						if (newDelta == 0)
							c.Hide();
						else
						{
							if (mdirection == Direction.Vertical)
							{
								c.Location = new Point(clientRect.X, delta);
								c.Width = clientRect.Width;
								c.Height = newDelta;
							}
							else
							{
								c.Location = new Point(delta, clientRect.Y);
								c.Height = clientRect.Height;
								c.Width = newDelta;
							}

							if (!c.Visible)
								c.Show();

							delta += newDelta;
						}
					}
				}
			}			
		}
        
		protected void OnControlResize(object sender, EventArgs e)
		{
			RepositionChildren();
		}
		
		#endregion

		#region Methods

		public TabGroupLeaf AddNewLeaf()
		{
			TabGroupLeaf tgl = new TabGroupLeaf(mtabbedGroups, this);
			Add(tgl);
			return tgl;
		}

		public TabGroupLeaf InsertNewLeaf(int index)
		{
			if (index < 0)
				throw new ArgumentOutOfRangeException("index", index, ResourceLibrary.GetString(CommonResourceKeys.LargerIndexThanZero, CommonResourceKeys.Root));
                
			if (index >= mchildren.Count)
				throw new ArgumentOutOfRangeException("index", index, ResourceLibrary.GetString(WindowsControlsResourceKeys.CantInsert, WindowsControlsResourceKeys.Root));

			TabGroupLeaf tgl = new TabGroupLeaf(mtabbedGroups, this);
            
			Insert(index, tgl);
            
			return tgl;                           
		}
            
		public void Remove(TabGroupBase group)
		{
			RemoveAt(mchildren.IndexOf(group));
		}

		public void RemoveAt(int index)
		{
			if (index < 0)
				throw new ArgumentOutOfRangeException("index", index, ResourceLibrary.GetString(CommonResourceKeys.LargerIndexThanZero, CommonResourceKeys.Root));
                
			if (index >= mchildren.Count)
				throw new ArgumentOutOfRangeException("index", index, ResourceLibrary.GetString(WindowsControlsResourceKeys.CantRemove, WindowsControlsResourceKeys.Root));

			if (mchildren[index] == mtabbedGroups.ActiveLeaf)
			{
				mtabbedGroups.MoveActiveToNearestFromLeaf(mchildren[index]);
			}

			TabGroupBase childRemoved = mchildren[index];
			
			mtabbedGroups.GroupRemoved(mchildren[index]);

			if (mchildren.Count == 1)
			{
				ControlUtilities.RemoveAt(mcontrol.Controls, 0);
			}
			else
			{
				int pos = 0;

				if (index != 0)
					pos = index * 2 - 1;

				ControlUtilities.RemoveAt(mcontrol.Controls, pos);
				ControlUtilities.RemoveAt(mcontrol.Controls, pos);
			}

			Decimal space = mchildren[index].Space;

			mchildren.RemoveAt(index);

			RemoveWindowSpace(space);

			RepositionChildren();

			if (mchildren.Count == 0)
			{
				if (mtabbedGroups.AutoCompact)
					mtabbedGroups.Compact();
			}
            
			mtabbedGroups.EnforceAtLeastOneLeaf();
            
			if (mtabbedGroups.AutoCalculateDirty)
				mtabbedGroups.Dirty = true;
		
			childRemoved.Dispose();
		}
        
		public int IndexOf(TabGroupBase group)
		{
			return mchildren.IndexOf(group);
		}
        
		public void Clear()
		{
			if (mchildren.IndexOf(mtabbedGroups.ActiveLeaf) != 0)
			{
				mtabbedGroups.MoveActiveToNearestFromSequence(this);
			}
        
			TabGroupBaseCollection copyChildren = new TabGroupBaseCollection();

			foreach(TabGroupBase tgb in mchildren)
			{
				copyChildren.Add(tgb);

				mtabbedGroups.GroupRemoved(tgb);
			}

			ControlUtilities.RemoveAll(mcontrol);

			mchildren.Clear();

			mcontrol.Invalidate();

			if (mtabbedGroups.AutoCompact)
				mtabbedGroups.Compact();
            
			mtabbedGroups.EnforceAtLeastOneLeaf();
            
			if (mtabbedGroups.AutoCalculateDirty)
				mtabbedGroups.Dirty = true;
		
			foreach(TabGroupBase tgb in copyChildren)
				tgb.Dispose();
		}
        
		public TabGroupBase this[int index]
		{
			get { return mchildren[index]; }
		}

		public void Rebalance(bool recurse)
		{
			if (mchildren.Count > 0)
			{
				Decimal newSpace = Decimal.Round(100m / mchildren.Count, SpacePrecision);

				foreach(TabGroupBase group in mchildren)
					group.Space = newSpace;

				Decimal remainderSpace = 100m - (newSpace * mchildren.Count);
                 
				if (remainderSpace != 0)
					mchildren[mchildren.Count - 1].Space += remainderSpace;
				        
				if (recurse)
				{
					foreach(TabGroupBase group in mchildren)
						if (group.IsSequence)
							(group as TabGroupSequence).Rebalance(recurse);
				}
			}
            
			RepositionChildren();
		}

		public void Compact()
		{
			Compact(mtabbedGroups.CompactOptions);
		}

		public void Compact(TabbedGroups.CompactFlags flags)
		{
			foreach(TabGroupBase tgb in mchildren)
				if (tgb.IsSequence)
					(tgb as TabGroupSequence).Compact(flags);
        
			CompactRemoveEmptyTabLeafs(flags);
			CompactRemoveEmptyTabSequences(flags);
            
			CompactReduceSingleEntries(flags);
            
			CompactReduceSameDirection(flags);
		}
        
		public void Reposition()
		{
			RepositionChildren();
		}

		internal void Replace(TabGroupBase orig, TabGroupBase replace)
		{
			int origPos = mchildren.IndexOf(orig);
            
			replace.RealSpace = orig.RealSpace;
            
			if (mchildren.Count == 1)
			{
				ControlUtilities.RemoveAt(mcontrol.Controls, 0);
			}
			else
			{
				int pos = 0;
				if (origPos != 0)
					pos = origPos * 2 - 1;


				ControlUtilities.RemoveAt(mcontrol.Controls, pos);
				ControlUtilities.RemoveAt(mcontrol.Controls, pos);
			}
            
			if (origPos == 0)
			{
				if (mchildren.Count > 1)
				{
					ResizeBar bar = new ResizeBar(mdirection, this);
                
					mcontrol.Controls.Add(bar);

					mcontrol.Controls.SetChildIndex(bar, 0);
				}            

				mcontrol.Controls.Add(replace.GrouparamControl);

				mcontrol.Controls.SetChildIndex(replace.GrouparamControl, 0);
			}
			else
			{
				ResizeBar bar = new ResizeBar(mdirection, this);
                
				mcontrol.Controls.Add(bar);

				mcontrol.Controls.Add(replace.GrouparamControl);
                    
				int	pos = origPos * 2 - 1;

				mcontrol.Controls.SetChildIndex(bar, pos++);
				mcontrol.Controls.SetChildIndex(replace.GrouparamControl, pos);
			}
            
			replace.SetParent(this);
            
			mchildren[origPos] = replace;
            
			RepositionChildren();

			if (mtabbedGroups.AutoCalculateDirty)
				mtabbedGroups.Dirty = true;
		}
        
		public bool CanResize(ResizeBar bar)
		{
			if (!mtabbedGroups.ResizeBarLock && (mtabbedGroups.ProminentLeaf == null))
			{
				int barIndex = mcontrol.Controls.IndexOf(bar);
                
				int beforeIndex = (barIndex - 1) / 2;

				TabGroupBase before = mchildren[beforeIndex];
				TabGroupBase after = mchildren[beforeIndex + 1];

				if (((before.Space <= 0m) && (after.Space <= 0m)))
					return false;
				else
					return true;
			}
			else
			{
				return false;
			}
		}

		public bool StartResizeOperation(ResizeBar bar, ref Rectangle screenBoundary)
		{
			int barIndex = mcontrol.Controls.IndexOf(bar);
            
			int beforeIndex = (barIndex - 1) / 2;

			TabGroupBase before = mchildren[beforeIndex];
			TabGroupBase after = mchildren[beforeIndex + 1];

			screenBoundary = mcontrol.RectangleToScreen(mcontrol.ClientRectangle);

			Rectangle rectBefore = before.GrouparamControl.RectangleToScreen(before.GrouparamControl.ClientRectangle);
			Rectangle rectAfter = after.GrouparamControl.RectangleToScreen(after.GrouparamControl.ClientRectangle);

			if (mdirection == Direction.Vertical)
			{
				screenBoundary.Y = rectBefore.Y + before.MinimumSize.Height;
				screenBoundary.Height -= screenBoundary.Bottom - rectAfter.Bottom;
				screenBoundary.Height -= after.MinimumSize.Height;
			}
			else
			{
				screenBoundary.X = rectBefore.X + before.MinimumSize.Width;
				screenBoundary.Width -= screenBoundary.Right - rectAfter.Right;
				screenBoundary.Width -= after.MinimumSize.Width;
			}

			return true;
		}
        
		public void EndResizeOperation(ResizeBar bar, int delta)
		{
			int barIndex = mcontrol.Controls.IndexOf(bar);
            
			int beforeIndex = (barIndex - 1) / 2;

			TabGroupBase before = mchildren[beforeIndex];

			DeltaGroupSpace(before, delta);
		
			if (mtabbedGroups.AutoCalculateDirty)
				mtabbedGroups.Dirty = true;
		}

		#endregion 

		#region Properties

		internal Control.ControlCollection ChildControls
		{
			get { return mcontrol.Controls; }
		}

		public override int Count               
		{ 
			get { return mchildren.Count; } 
		}
            
		public override bool IsLeaf             
		{ 
			get { return false; } 
		}
        
		public override bool IsSequence         
		{ 
			get { return true; } 
		}
        
		public override Control GrouparamControl    
		{ 
			get { return mcontrol; } 
		}
        
		public Direction Direction
		{
			get { return mdirection; }
            
			set
			{
				if (mdirection != value)
				{
					mdirection = value;
					RepositionChildren();
				}
			}
		}

		public int ResizeBarVector      { get { return mtabbedGroups.ResizeBarVector;   } }
		public Color ResizeBarColor     { get { return mtabbedGroups.ResizeBarColor;    } }        
		public Color BackgroundColor    { get { return mtabbedGroups.BackColor;         } }

		#endregion

    }
}
